using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Cysharp.Threading.Tasks;
using GraphProcessor;
using IQIGame.Onigao.Framework;
using Sirenix.Utilities;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

namespace IQIGame.Onigao.GamePlay.Editors
{
    public class LvServiceSerachWindow : EditorWindow
    {
        private EnumField EF_SearchType;
        private TextField TF_SearchTxt;
        private Button Btn_Search;
        private Button Btn_CheckServiceID;
        private Button Btn_ReloadTable;
        private Button Btn_CheckExecutionData;

        [MenuItem("ToolApp/关卡编辑器/服务搜索", false, 90)]
        static void ShowWindow()
        {
            var wnd = GetWindow<LvServiceSerachWindow>();
            wnd.minSize = new Vector2(200, 400);
            wnd.Show(true);
        }

        public void CreateGUI()
        {
            // Import UXML
            var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/ScriptS/GamePlay/Editor/LevelEditor/LevelService/Window/LvServiceSerachWindow.uxml");
            VisualElement root = visualTree.Instantiate();
            this.rootVisualElement.Add(root);

            this.EF_SearchType = root.Q<EnumField>("EF_SearchType");
            this.EF_SearchType.Init(ELevelServiceSerachType.ServiceID);
            this.TF_SearchTxt = root.Q<TextField>("TF_SearchTxt");
            this.Btn_Search = root.Q<Button>("Btn_ServiceSearch");
            this.Btn_Search.clicked += OnClickBtnSearch;

            this.Btn_CheckServiceID = root.Q<Button>("Btn_CheckServiceID");
            this.Btn_CheckServiceID.clicked += OnClickBtnCheckServiceID;

            this.Btn_ReloadTable = root.Q<Button>("Btn_ReloadTable");
            this.Btn_ReloadTable.clicked += OnClickBtnReloadTable;

            this.Btn_CheckExecutionData = root.Q<Button>("Btn_CheckExecutionData");
            this.Btn_CheckExecutionData.clicked += OnClickBtnCheckExecutionData;
        }

        private void OnEnable()
        {
            TableExportMenu.onExportExcel += this.OnClickBtnReloadTable;
        }

        private void OnDisable()
        {
            this.Btn_Search.clicked -= OnClickBtnSearch;
            this.Btn_CheckServiceID.clicked -= OnClickBtnCheckServiceID;
            this.Btn_ReloadTable.clicked -= OnClickBtnReloadTable;
            this.Btn_CheckExecutionData.clicked -= OnClickBtnCheckExecutionData;

            TableExportMenu.onExportExcel -= this.OnClickBtnReloadTable;
        }

        #region ClickBtn

        private void OnClickBtnSearch()
        {
            var rAllGraph = LevelServiceBlackboard.Instance.GetAllGraph();
            var rObjList = new List<UnityEngine.Object>();
            Func<BaseGraph, bool> rSearchCheck = null;
            var rInput = this.TF_SearchTxt.value.Trim();
            switch (this.EF_SearchType.value)
            {
                case ELevelServiceSerachType.ServiceID:
                    {
                        var nServiceID = int.Parse(rInput);
                        rSearchCheck = (x) => this.GraphWithServiceID(x, nServiceID);
                        break;
                    }
                case ELevelServiceSerachType.ExecutionGroup:
                    {
                        var nServiceGroup = rInput;
                        rSearchCheck = (x) => this.GraphWithExecutionGroup(x, nServiceGroup);
                        break;
                    }
            }

            for (int i = 0; i < rAllGraph.Count; i++)
            {
                var rGraph = rAllGraph[i];
                var bHasTargetNode = rSearchCheck?.Invoke(rGraph) ?? false;
                if (bHasTargetNode)
                {
                    rObjList.Add(rGraph);
                    LogGame.Log(AssetDatabase.GetAssetPath(rGraph));
                }
            }
            Selection.objects = rObjList.ToArray();
        }

        private void OnClickBtnCheckServiceID()
        {
            if (LevelServiceBlackboard.Instance.editorCache.allPathToService?.Count <= 0)
            {
                LogGame.LogError("未找到缓存数据，全部导出后再进行检查");
                return;
            }
            var rGraphs = LevelServiceBlackboard.Instance.GetAllGraph();
            var rObjList = new List<UnityEngine.Object>();
            var rAllServiceID = new HashSet<int>();
            foreach (var rPair in LevelServiceBlackboard.Instance.editorCache.allPathToService)
            {
                for (int i = 0; i < rPair.Value.Count; i++)
                {
                    if (!rAllServiceID.Add(rPair.Value[i]))
                    {
                        LogGame.LogError($"[{rPair.Key}]服务有重复ID[{rPair.Value[i]}]");
                    }
                }
            }
            foreach (var rGraph in rGraphs)
            {
                bool bPass = true;
                foreach (var rNode in rGraph.nodes)
                {
                    var rFields = rNode.GetType().GetFields();
                    foreach (var rField in rFields)
                    {
                        if (!CheckServiceGuid(rField, rNode, rAllServiceID, out bPass) &&
                            rField.FieldType.IsGenericType && rField.FieldType.GetGenericTypeDefinition() == typeof(List<>))
                        {
                            var rArr = (IEnumerable)rField.GetValue(rNode);
                            foreach (var rItem in rArr)
                            {
                                var rChildFields = rItem.GetType().GetFields();
                                foreach (var rChildField in rChildFields)
                                {
                                    CheckServiceGuid(rChildField, rItem, rAllServiceID, out bPass);
                                    if (!bPass) break;
                                }
                                if (!bPass) break;
                            }
                        }
                        if (!bPass) break;
                    }
                    if (!bPass) break;
                }
                if (!bPass)
                {
                    LogGame.LogError($"【{AssetDatabase.GetAssetPath(rGraph)}】存在无效ID");
                    rObjList.Add(rGraph);
                }
            }
            if (rObjList.Count > 0)
            {
                Selection.objects = rObjList.ToArray();
            }

            bool CheckServiceGuid(FieldInfo field, object obj, HashSet<int> allService, out bool pass)
            {
                var rAttr = field.GetAttribute<LevelServiceEditorCustomPropertyAttribute>();
                pass = true;
                if (rAttr != null)
                {
                    var rConfig = LevelServiceEditorSettingGlobal.GetConfig(rAttr.key);
                    if (rConfig != null && (rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.GraphToServiceGroup) > 0)
                    {
                        var nGUID = (int)field.GetValue(obj);
                        pass = allService.Contains(nGUID);
                    }
                    return true;
                }
                return false;
            }
        }

        private void OnClickBtnReloadTable()
        {
            this.LoadTable().Forget();
        }

        private void OnClickBtnCheckExecutionData()
        {
            if (TableCenter.buff == null)
            {
                LogGame.LogError("未加载配置表，稍后重试");
                this.LoadTable().Forget();
                return;
            }
            var rAllGraph = LevelServiceBlackboard.Instance.GetAllGraph();
            List<UnityEngine.Object> rNotPass = new List<UnityEngine.Object>();
            for (int i = 0; i < rAllGraph.Count; i++)
            {
                bool bPass = true;
                var rGraph = rAllGraph[i];
                for (int j = 0; j < rGraph.nodes.Count; j++)
                {
                    var rNode = rGraph.nodes[j];
                    var rType = rNode.GetType();
                    var rFields = rType.GetFields();
                    for (int k = 0; k < rFields.Length; k++)
                    {
                        var rField = rFields[k];
                        var rAttr = rField.GetCustomAttribute<LevelServiceEditorCustomPropertyAttribute>();
                        if (rAttr != null)
                        {
                            var rVisibleAttr = rField.GetCustomAttribute<VisibleIf>();
                            if (rVisibleAttr != null && rType.GetField(rVisibleAttr.fieldName).GetValue(rNode) != rVisibleAttr.value)
                            {
                                continue; // 被隐藏状态，不验证
                            }
                            var rConfig = LevelServiceEditorSettingGlobal.GetConfig(rAttr.key);
                            if (rConfig == null)
                            {
                                continue;
                            }
                            if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.InputInt) > 0)
                            {
                                continue; // 输入可以输入任何值
                            }
                            if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.TableID) > 0)
                            {
                                if (rField.FieldType.IsGenericType && rField.FieldType.GetGenericTypeDefinition() == typeof(List<>))
                                {
                                    var rValueList = (List<int>)rField.GetValue(rNode);
                                    for (int l = 0; l < rValueList.Count; l++)
                                    {
                                        var nValue = rValueList[l];
                                        if (!Check(nValue, out bool bHasCustomInt))
                                        {
                                            bPass = false;
                                            var rAssetPath = AssetDatabase.GetAssetPath(rGraph);
                                            LogGame.LogError($"[{rAssetPath}]中[{rNode.name}]的[{rField.Name}]数据检测未通过[{nValue}]不在配置表[{rConfig.tableName}]中{(bHasCustomInt ? "且不符合自定配置" : "")}");
                                        }
                                    }
                                }
                                else
                                {
                                    int nValue = 0;
                                    if (rField.FieldType == typeof(int))
                                    {
                                        nValue = (int)rField.GetValue(rNode);
                                    }
                                    else if (rField.FieldType == typeof(byte))
                                    {
                                        nValue = (byte)rField.GetValue(rNode);
                                    }
                                    else
                                    {
                                        LogGame.LogError(rField);
                                        continue;
                                    }
                                    if (!Check(nValue, out bool bHasCustomInt))
                                    {
                                        bPass = false;
                                        var rAssetPath = AssetDatabase.GetAssetPath(rGraph);
                                        LogGame.LogError($"[{rAssetPath}]中[{rNode.name}]的[{rField.Name}]数据检测未通过[{nValue}]不在配置表[{rConfig.tableName}]中{(bHasCustomInt ? "且不符合自定配置" : "")}");
                                    }
                                }

                                bool Check(int value, out bool hasCustomInt)
                                {
                                    hasCustomInt = false;
                                    var rTable = this.GetProperty(typeof(TableCenter), rConfig.tableName)?.GetValue(null);
                                    var rDict = this.GetProperty(rTable?.GetType(), "DataMap")?.GetValue(rTable) as IDictionary;
                                    if (rDict?.Contains(value) ?? false)
                                    {
                                        return true; // 检测通过
                                    }
                                    hasCustomInt = (rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.CustomInt) > 0;
                                    if (hasCustomInt && rConfig.value.ContainsKey(value))
                                    {
                                        return true;
                                    }
                                    return false;
                                }
                            }
                        }
                    }
                }
                if (!bPass)
                {
                    rNotPass.Add(rGraph);
                }
            }

            if (rNotPass.Count > 0)
            {
                Selection.objects = rNotPass.ToArray();
            }

            LogGame.Log("检测完成");
        }

        #endregion

        private async UniTaskVoid LoadTable()
        {
            await TableCenter.LoadTables();
            LogGame.Log("关卡服务配置表缓存重载完成");
        }

        private bool GraphWithServiceID(BaseGraph graph, int serviceID)
        {
            return graph.nodes.Exists((x) =>
            {
                if (x is LevelServiceTriggerNode rTrNode)
                {
                    return IDGenerateNode.LondIDToInt2(rTrNode.GUIDLong) == serviceID;
                }
                return false;
            });
        }

        private bool GraphWithExecutionGroup(BaseGraph graph, string serviceGroup)
        {
            return graph.nodes.Exists((x) =>
            {
                if (x is LevelServiceExecutionNode rExecNode)
                {
                    return rExecNode.executionGroupID == serviceGroup;
                }
                return false;
            });
        }

        private PropertyInfo GetProperty(Type type, string name)
        {
            if (type == null || string.IsNullOrEmpty(name))
            {
                return null;
            }
            var rProperties = type.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            for (int i = 0; i < rProperties.Length; i++)
            {
                if (rProperties[i].Name.ToLower() == name.ToLower())
                {
                    return rProperties[i];
                }
            }
            return null;
        }
    }

    public enum ELevelServiceSerachType
    {
        [InspectorName("服务ID")] ServiceID,
        [InspectorName("执行组")] ExecutionGroup
    }
}